﻿/*
   Open Intel 
   Copyright © 2011 – ISC. All Rights Reserved.
*/

using System;
using System.Collections.Generic;
using Caliburn.Micro;
using ISC.MapDotNetServer.Common;
using ISC.MapDotNetServer.Common.Data;
using ISC.RIM.Silverlight.Projections;
using OI.BingGeocodeService;
using OI.Framework;

namespace OI.Async
{
    public class BingGeocode : IResult
    {
        #region DATA

        public string AddressString { get; private set; }
        public QueryResultTable Results { get; private set; }

        #endregion

        public BingGeocode(string addressString)
        {
            AddressString = addressString;
        }

        #region IResult Members

        public void Execute(ActionExecutionContext context)
        {
            if (!string.IsNullOrEmpty(AddressString) && 
                Utility.IsValidStreetAddress(AddressString))
            {
                // scrub for ending city, state and country
                // we do not require user to enter these since this solution knows the jurisdiction
                string addStr = AddressString.Trim();
                bool endsInCountry = addStr.EndsWith(Configuration.Jurisdiction.Country, StringComparison.CurrentCultureIgnoreCase);
                bool endsInState = addStr.EndsWith(Configuration.Jurisdiction.State, StringComparison.CurrentCultureIgnoreCase);
                bool endsInStateCode = addStr.EndsWith(Configuration.Jurisdiction.StateCode, StringComparison.CurrentCultureIgnoreCase);
                bool endsInCity = addStr.EndsWith(Configuration.Jurisdiction.City, StringComparison.CurrentCultureIgnoreCase);
                
                if (!endsInCity && !endsInStateCode && !endsInState && !endsInCountry)
                {
                    addStr += " " + Configuration.Jurisdiction.City + ", " + Configuration.Jurisdiction.State + ", " + Configuration.Jurisdiction.Country;
                }
                else if (!endsInStateCode && !endsInState && !endsInCountry)
                {
                    addStr += ", " + Configuration.Jurisdiction.State + ", " + Configuration.Jurisdiction.Country;
                }
                else if (!endsInCountry)
                {
                    addStr += ", " + Configuration.Jurisdiction.Country;
                }

                // build request
                var request = new GeocodeRequest
                {
                    Credentials = new Credentials
                    {
                        ApplicationId = Configuration.BingServiceKey
                    },
                    Query = addStr,
                    Options = new GeocodeOptions
                    {
                        Count = 5,
                        Filters = new List<FilterBase>()
                    }
                };

                // set low cofidence
                request.Options.Filters.Add(
                    new ConfidenceFilter
                        {
                            MinimumConfidence = Confidence.Low
                        }
                    );

                // execute call
                var client = new GeocodeServiceClient();
                client.GeocodeCompleted += ClientGeocodeCompleted;
                client.GeocodeAsync(request);
            }
            else
            {
                // do nothing
                Completed(this, new ResultCompletionEventArgs());
            }
        }


        private void ClientGeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
        {
            try
            {
                if (e.Error != null)
                {
                    throw (e.Error);
                }

                if (e.Result.Results.Count > 0)
                {
                    // create a new QueryResultTable so results can be treated just like a spatial query
                    Results = new QueryResultTable
                    {
                        Name = "Address results",
                        Fields = new List<string>
                    {
                        "Address",
                        "Confidence"
                    },
                        QueryResultRows = new List<QueryResultRow>(),
                    };

                    // loop through results and build resultset
                    foreach (var r in e.Result.Results)
                    {
                        var row = new QueryResultRow
                        {
                            Values = new List<string>
                            {
                                r.DisplayName,
                                r.Confidence.ToString(),
                            },
                        };

                        // transform bing lat/lon to spherical mercator
                        var pt = new System.Windows.Point(r.Locations[0].Longitude, r.Locations[0].Latitude);
                        var mercPt = Utility.SphericalMercatorProj.ConvertLatLonToMapUnit(pt);
                        row.Shape = new Point(mercPt.X, mercPt.Y);

                        Results.QueryResultRows.Add(row);
                    }
                }
            }
            catch (Exception ex)
            {
                IoC.Get<IShell>().HandleException(ex, "Error geocoding:");
            }
            finally
            {
                Completed(this, new ResultCompletionEventArgs { Error = e.Error });
            }
        }


        public event EventHandler<ResultCompletionEventArgs> Completed;

        #endregion
    }
}